#ifndef QTI_SPITEST_H
#define QTI_SPITEST_H
#include <sys/types.h>

#define PACKAGE_HEADER_SIZE_BYTE (4)
#define PACKAGE_CRC16_SIZE_BYTE (2)
#define PACKAGE_DUMMY_SIZE_BYTE (4)
#define PACKAGE_BODY_SIZE_MAX_BYTE (128 + 32)
#define BUFFER_SIZE_BYTE (PACKAGE_BODY_SIZE_MAX_BYTE + PACKAGE_HEADER_SIZE_BYTE + PACKAGE_CRC16_SIZE_BYTE + PACKAGE_DUMMY_SIZE_BYTE)

typedef struct
{
    /* data */
    // header include 'M/S' + 'O' + length of data in body
	uint8_t header[PACKAGE_HEADER_SIZE_BYTE];	 // 4 byte
	uint8_t dummy[PACKAGE_DUMMY_SIZE_BYTE];      // 4 byte
	uint8_t body[PACKAGE_BODY_SIZE_MAX_BYTE];	 // 128+32 byte
	uint8_t crc16[PACKAGE_CRC16_SIZE_BYTE]; 	 // 2 byte

} data_package_t;

typedef enum host_status
{
	IS_HOST 					  = 'M',
	IS_SLAVE					  = 'S',
	IS_UNKNOW,
} host_status_t;

typedef enum function_cmd
{
	READ_CMD					   = 'R',
	WRITE_CMD                      = 'W',
	WREAD_CMD                      = 'T',
}function_cmd_t;

typedef enum can_command
{
    CAN_CMD_RESET_COUNTERS         = '0',
	CAN_CMD_BOOTLOADER             = '@',
	CAN_CMD_SEND_FRAME             = 'C',
	CAN_CMD_INIT_FILTERS_CONFIG    = 'F',
	CAN_CMD_RESET_SYSTEM           = 'H',
	CAN_CMD_JUMP_TO_BOOTLOADER     = 'J',
    CAN_CMD_WATCHDOG_KICK          = 'K',
    CAN_CMD_BOOTQUERY              = 'Q',
	CAN_CMD_START_STOP             = 'S',
	CAN_CMD_GET_RESET_CAUSE        = 'U',
	CAN_CMD_GET_VERSION            = 'V',
	CAN_CMD_GET_POWERUP_COUNTERS   = 'Y',
	CAN_CMD_DUMP_DEBUG_DATA        = 'Z',

} can_command_t;

typedef enum can_response
{
    CAN_RSP_RESET_COUNTERS         = '0',
	CAN_RSP_BOOTLOADER             = '@',
	CAN_RSP_SEND_FRAME_RECV        = 'c',
	CAN_RSP_RECV_CAN_DATA	       = 'd',
	CAN_RSP_INIT_FILTERS_CONFIG    = 'f',
	CAN_RSP_RESET_SYSTEM           = 'h',
	CAN_RSP_JUMP_TO_BOOTLOADER     = 'j',
	CAN_RSP_WATCHDOG_KICK          = 'k',
	CAN_RSP_MCU_RESET_HELLO        = 'r',
	CAN_RSP_START_STOP             = 's',
	CAN_RSP_BOOTMODE               = 'q',
	CAN_RSP_GET_RESET_CAUSE        = 'u',
	CAN_RSP_GET_VERSION            = 'v',
	CAN_RSP_GET_POWERUP_COUNTERS   = 'y',
	CAN_RSP_DUMP_DEBUG_DATA        = 'z',

} can_response_t;

typedef struct can_filter_config
{
    uint8_t  id[4];
	uint8_t  mask[4];
	/* The MCP25xx CAN FD controller supportes multiple operating modes.
	 * See MCP25xx Reference Manual for more details.
	 *
	 * MONET Application only supports/uses two CAN modes -- normal and silent (i.e. listen only).
	 * 0 -> normal operation mode.
	 * 1 -> silent operation mode
	 */
	uint8_t   mode;     /* See MCP25xx Reference Manual for all operating modes. */
	uint8_t   handle;

} can_filter_config_t;

typedef struct can_config
{
    uint8_t   mode;     /* See MCP25xx Reference Manual for all operating modes. */
	uint8_t   bitrate[4];
	uint8_t   num_filters;
	can_filter_config_t filters[];

} can_config_t;

#define CAN_ID_STD                  (0x00000000U)  /*!< Standard Id */
#define CAN_ID_EXT                  (0x00000004U)  /*!< Extended Id */
#define CAN_RTR_DATA                (0x00000000U)  /*!< Data frame */
#define CAN_RTR_REMOTE              (0x00000002U)  /*!< Remote frame */
/* The definitions are in parentheses to match definitions in MCU HAL */

typedef struct can_data
{
	/* MsgType is one of MonetCANMessageType */
	uint8_t MsgType[4];

	/* StdId specifies the standard identifier, valid only if IDE is CAN_ID_STD.
	This parameter is an 11 bit number between 0 and 0x7FF */
	uint8_t StdId[4];

	/* ExtId specifies the extended identifier, valid only if IDE is CAN_ID_EXT.
	This parameter is a 29 bit number between 0 and 0x1FFFFFFF */
	uint8_t ExtId[4];

	/* IDE specifies the type of identifier for the message that will be transmitted.
	This parameter can be either CAN_ID_STD or CAN_ID_EXT */
	uint8_t IDE[4];

	/*!< Specifies the type of frame for the message that will be transmitted.
	This parameter can be either CAN_RTR_DATA or CAN_RTR_REMOTE */
	uint8_t RTR[4];

	/*DLC specifies the length of the frame that will be transmitted.
	This parameter must be a number between 1 and 8 */
	uint8_t DLC[4];

	/* Contains the data to be transmitted, up to 8 bytes. */
	uint8_t Data[8];

} can_data_t;

typedef enum MonetCANMessageType
{
	CAN_RECEIVE_MESSAGE = 0,    //Receive regular message from CAN bus
	CAN_ERROR_MESSAGE   = 1,    //Receive error message from CAN bus
	CAN_SEND_SUCCESSFUL = 2,    //Send data OK to the CAN bus
	CAN_SEND_FAILED     = 3,    //Send data failed to CAN bus

} MonetCANMessageType_t;

typedef struct can_updata_monitor
{
    uint32_t   app_size;            // size of app .bin file
    uint32_t   app_crc;             // crc of app .bin file
    /*Total number of slices sliced based on 128 bytes. 
    e.g app_size = 36587, num_slices = ( 36587 % 128 ) ? ( 36587 / 128 + 1 ) : ( 36587 / 128 ).*/
    uint32_t   num_slices;  
    /*  If parameter is 0, the mcu clears the received data and starts receiving the.bin file again. 
    This parameter can only be incremented one by one, otherwise an error is reported from mcu, and 
    this parameter are not updated in mcu */
    uint32_t   current_slice_num;   

} can_updata_monitor_t;

typedef struct CAN_CMD_BOOTLOADER_CMD_DATA
{
    can_updata_monitor_t monitor;
    uint8_t data[128];

} CAN_CMD_BOOTLOADER_CMD_DATA;

typedef struct CAN_CMD_BOOTLOADER_RSP_DATA
{
    can_updata_monitor_t monitor;
    /*
    0: Received successfully. 
    1: The .bin file is successfully verified. 
    2: current_slice_num dose not increment one by one.
    */
    uint8_t error; 

} CAN_CMD_BOOTLOADER_RSP_DATA;



static int package_data (uint8_t *pbuff, int len, unsigned char status);

static uint16_t Updatecrc16(uint16_t crcin, uint8_t byte);

uint16_t cal_crc16(const uint8_t *data, uint32_t size);

static void data_fill_crc16(data_package_t *p_data);

static int spi_init_config(void);

static int spi_transfer_config(uint8_t *txpbuff, uint8_t *rxpbuff, int len);

static int spi_write_config(uint8_t *pbuff, int len);

static int spi_read_config(uint8_t *pbuff, int len);

static int spi_close_config(void);

static int spi_communication_mode(void);

static unsigned int spi_get_func_code(void);

static void spi_test_poll(void);

static void hex_dump(const void *src, size_t length, size_t line_size,

             char *prefix);

#endif